home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 8: LINUX Games / Linux Cubed Series 8 - LINUX Games.iso / games / video / pictetri.src / pictetri / pictetris-src / game.c < prev    next >
C/C++ Source or Header  |  1995-12-19  |  11KB  |  337 lines

  1. /***************************************************************************\
  2. |*                                       *|
  3. |*  game.c:    A version of Tetris to run on Linux SVGAlib console.       *|
  4. |*        This is the module that actually plays the game.       *|
  5. |*                                       *|
  6. |*  Authors:    Mike Taylor (mirk@uk.ac.warwick.cs) &               *|
  7. |*        Arturo Espinosa (arturo@nuclecu.unam.mx)           *|
  8. |*  Started:    Fri May 26 12:26:05 BST 1989 (tetris for terminals)       *|
  9. |*            Dic 1, 1995 (pictetris)                       *|
  10. |*                                       *|
  11. \***************************************************************************/
  12.  
  13. #include <sys/types.h>
  14. #include <sys/time.h>
  15. #include <stdio.h>
  16. #include <errno.h>
  17.  
  18. /* Here's what is need for this under Linux */
  19. void l_usleep (unsigned long usec)
  20. {
  21.   struct timeval timeout;
  22.  
  23.   timeout.tv_sec = usec / 1000000;
  24.   timeout.tv_usec = usec - 1000000 * timeout.tv_sec;
  25.   select (1, NULL, NULL, NULL, &timeout);
  26. }
  27.  
  28. #include "pictetris.h"
  29. #include "game.h"
  30. #include "screen.h"
  31. #include "pieces.h"
  32. #include "utils.h"
  33.  
  34. /*-------------------------------------------------------------------------*/
  35.  
  36. extern long int random ();
  37. extern int rand_lines;             /* Garbage lines at the start of the game */
  38. extern int piece_no_next;          /* The next piece to appear... */
  39. extern int orient_next;            /* next piece orientation */
  40. extern int next_box;               /* Flag for the next-piece box */
  41. extern int sound;             /* Sound flag */
  42. extern int total_time;
  43.  
  44. /*-------------------------------------------------------------------------*/
  45.  
  46. char left_key    = LEFT_KEY;    /* Move piece left */
  47. char right_key    = RIGHT_KEY;    /* Move piece right */
  48. char rotate_key = ROTATE_KEY;    /* Rotate piece anticlockwise */
  49. char drop_key    = DROP_KEY;    /* Drop piece to bottom of screen */
  50. char susp_key    = SUSP_KEY;    /* Suspend.  I'm sorry if its confusing */
  51. char quit_key    = QUIT_KEY;    /* Quit.  I'm sorry if its confusing */
  52.  
  53.    int piece_no_next;           /* The next piece to appear... */
  54.    int orient_next;             /* next piece orientation */
  55.  
  56. /***************************************************************************\
  57. |*                                       *|
  58. |*  Oh good grief, what on earth is the point of putting a huge, wobbly       *|
  59. |*  box-comment in front of this titchy little self-explanatory function?  *|
  60. |*  The name tells the whole story, it's perfectly strightforward, it's       *|
  61. |*  not a proposition from Witgenstein.     I wouldn't bother commenting it   *|
  62. |*  at all if it wasn't for the fact that I know I'd feel guilty in the       *|
  63. |*  morning.  I mean, be fair, you don't really want a program where all   *|
  64. |*  the functions *except one* have box-comments explaining them, do you?  *|
  65. |*  Ah well, here we go for completion's sake:                   *|
  66. |*                                       *|
  67. |*  The function clear_board() takes no parameters and returns no value.   *|
  68. |*  It clears the board.  The end.                       *|
  69. |*                                       *|
  70. \***************************************************************************/
  71.  
  72. void clear_board ()
  73. {
  74.   int i, j;
  75.  
  76.   for (i = 0; i < GAME_DEPTH+4; i++)
  77.     for (j = 0; j < GAME_WIDTH; j++)
  78.       board[i][j] = PI_EMPTY;
  79. }
  80.  
  81. /***************************************************************************\
  82. |*                                       *|
  83. |*  The function play_game is the main loop in which the game of Tetris       *|
  84. |*  is implemented.  It takes no parameters, and returns no value.  The       *|
  85. |*  time at which it returns no value is the end of a game.  The main       *|
  86. |*  loop-component is a select(2) which polls the keyboard in real-time.   *|
  87. |*  If you use a non-Berkeley UNIX(tm), you're well cheesed.           *|
  88. |*                                       *|
  89. |*  Actually, I have to admit I'm not proud of this one.  It must be one   *|
  90. |*  of the messiest functions I've written in years, in terms of nested       *|
  91. |*  loops with ad-hoc exit conditions, re-used variables, general       *|
  92. |*  obfuscation and so on.  I wanna make it quite clear that I make no       *|
  93. |*  apologies for my use of "goto", which remains a highly desirable       *|
  94. |*  language feature, and is still the most elegant way of coding many       *|
  95. |*  things, but I gotta admit, overall this one is bit of a chicken.       *|
  96. |*                                       *|
  97. \***************************************************************************/
  98.  
  99. void play_game ()
  100. {
  101.   int i;            /* Position of origin down board */
  102.   int j;            /* Position of origin across board */
  103.   int k;            /* Loop variable when i,j are invariant */
  104.    int l;                       /* Yet another loop variable... */
  105.    int piece_no;            /* Type of piece currently falling */
  106.   int orient;            /* Which way it is facing */
  107.   int pause_flag = 0;        /* We won't pause unless told to */
  108.   int presses_left;        /* Futher moves possible this drop */
  109.   int free_left = game_level;    /* Number of pieces to drop at start */
  110.   fd_set read_fds;        /* Select must look at stdin */
  111.    int time_passed;         /* Counts the time it has passed */
  112.    int sel_impostor = 0;        /* fake select... couldn't do it other way */
  113.    int dif_levels;               /* new scoring: more levels score better */
  114.    struct timeval timeout;    /* Time before piece drops in select(2) */
  115.   char ch;            /* Keystroke (command) */
  116.  
  117.   score = no_levels = no_pieces = 0;
  118.   update_scores ();
  119.   clear_board ();
  120.  
  121.    for(i=19;i>19-rand_lines;i--)
  122.      for(j=0;j<10;j++)                               /* Place garbage lines */
  123.      board[i+4][j]=(PI_EMPTY * (int) (random() % 2));
  124.    
  125.    draw_board();
  126.      
  127.     piece_no = (int) (random () % NO_PIECES);   /* Pick the first piece to */
  128.     orient = (int) (random () % NO_ORIENTS);    /* appear. */
  129.  
  130.    while (1) {
  131.  
  132.       piece_no_next = (int) (random () % NO_PIECES);  /* Pick the next piece */
  133.     orient_next = (int) (random () % NO_ORIENTS);     /* each time */
  134.  
  135.       if (next_box) draw_next_piece_box(piece_no_next,orient_next);
  136.       
  137.     i = -2;            /* Start falling from off-screen */
  138.     if (free_left > 0)        /* If we have random starting-pieces */
  139.       j = 1 + (int) (random () % (GAME_WIDTH-2));
  140.     else            /* places them randomly, otherwise */
  141.       j = GAME_WIDTH/2;     /* put the piece in the middle */
  142.  
  143.     if (!can_place (piece_no, orient, i, j)) {
  144.       for (k = 0; k < 9; k++) { /* Crude but (hopefully) effective */
  145.     draw_piece (piece_no, orient, i, j, PD_ERASE);
  146.     myrefresh (); l_usleep (80000);
  147.     draw_piece (piece_no, orient, i, j, PD_DRAW);
  148.     myrefresh (); l_usleep (80000);
  149.       }
  150.       break;            /* End of game - piece won't fit */
  151.     }
  152.  
  153.     if (free_left != 0) {    /* If there are pieces to be dropped, */
  154.       if (free_left > 0)    /* And the number is positiive, */
  155.     free_left--;        /* Then decrement it, otherwise */
  156.       else            /* increment it, in any case, bring */
  157.     free_left++;        /* it closer to zero if it gets to zero */
  158.       if (free_left == 0)    /* set a flag so that the game will */
  159.     pause_flag = 1;        /* pause.  Then go to the bit of code */
  160.       goto DROP_PIECE;        /* that drops it. */
  161.     }
  162.      
  163.     while (1) {
  164.       presses_left = NO_MOVES;
  165.       draw_piece (piece_no, orient, i, j, PD_DRAW);
  166.       update_scores ();
  167.       myrefresh ();
  168.  
  169.       while (1) {
  170.      check_pic_change();
  171.      
  172.      do  {
  173.         sel_impostor=0;
  174.         l_usleep(2000);
  175.         if (scan_key(quit_key)) sel_impostor=quit_key;
  176.         if (scan_key(susp_key)) sel_impostor=susp_key;
  177.         if (scan_key(DOWN_KEY)) time_passed=total_time/2000;
  178.          if (scan_key(drop_key)) sel_impostor=drop_key;
  179.         if (scan_key(rotate_key)) sel_impostor=rotate_key;
  180.         if (scan_key(left_key)) sel_impostor=left_key;
  181.         if (scan_key(right_key)) sel_impostor=right_key;
  182.         time_passed++;
  183.          flush_keyboard();
  184.      } while ((time_passed<total_time/2000)&&(sel_impostor==0));
  185.      
  186.      if (time_passed>=total_time/2000) time_passed=0;
  187.  
  188.      switch (sel_impostor)  {
  189.            
  190.     case 0:
  191.       goto TIMEOUT;
  192.     default:
  193.      ch=sel_impostor;
  194.       if (ch == REFRESH_KEY)
  195.         hoopy_refresh ();
  196.  
  197.       if ((ch != left_key) && (ch != right_key) && (ch != rotate_key) &&
  198.           (ch != drop_key) && (ch != quit_key) && (ch != susp_key))
  199.         break;
  200.  
  201.       presses_left--;
  202.       if (ch == left_key) {
  203.         if (can_place (piece_no, orient, i, j-1)) {
  204.           draw_piece (piece_no, orient, i, j, PD_ERASE);
  205.           j--;
  206.           draw_piece (piece_no, orient, i, j, PD_DRAW);
  207.           myrefresh ();
  208.         }
  209.       }
  210.  
  211.       else if (ch == right_key) {
  212.         if (can_place (piece_no, orient, i, j+1)) {
  213.           draw_piece (piece_no, orient, i, j, PD_ERASE);
  214.           j++;
  215.           draw_piece (piece_no, orient, i, j, PD_DRAW);
  216.           myrefresh ();
  217.         }
  218.       }
  219.  
  220.       else if (ch == rotate_key) {
  221.         int new_or = ((rotate_backwards == 0) ? ((orient+1)%NO_ORIENTS) :
  222.               ((orient-1)%NO_ORIENTS+NO_ORIENTS*(orient == 0)));
  223.         if (can_place (piece_no, new_or, i, j)) {
  224.           draw_piece (piece_no, orient, i, j, PD_ERASE);
  225.           orient = new_or;
  226.           draw_piece (piece_no, orient, i, j, PD_DRAW);
  227.           myrefresh ();
  228.         }
  229.       }
  230.  
  231.       else if (ch == drop_key) {
  232.       DROP_PIECE:
  233.         while (can_place (piece_no, orient, i+1, j)) {
  234.           draw_piece (piece_no, orient, i, j, PD_ERASE);
  235.           i++;
  236.           draw_piece (piece_no, orient, i, j, PD_DRAW);
  237.           myrefresh ();
  238.         }
  239.         goto TIMEOUT;
  240.       }
  241.  
  242.       else if (ch == quit_key)
  243.         return;
  244.  
  245.       else if (ch == susp_key) {
  246.         print_msg ("Paused");
  247.          flush_keyboard();
  248.          get_keyboard_key();
  249.          draw_area();
  250.          hoopy_refresh();
  251.       }
  252.  
  253.       break;
  254.     }
  255.       }
  256.  
  257.     TIMEOUT:
  258.       if (!can_place (piece_no, orient, i+1, j)) {
  259.     place_piece (piece_no, orient, i, j);
  260.     score += pieces[piece_no].points;
  261.     no_pieces++;
  262.     update_scores ();
  263.     myrefresh ();
  264.  
  265.     dif_levels=no_levels;
  266.     for (i = 0; i < GAME_DEPTH; i++) {
  267.       for (j = 0; j < GAME_WIDTH; j++)
  268.         if (board[i+4][j] == PI_EMPTY)
  269.           break;
  270.  
  271.       if (j == GAME_WIDTH) {
  272.          no_levels++;
  273.          for (l=0;l<2;l++)  {
  274.         for (k=0;k<GAME_WIDTH;k++)
  275.           board[i+4][k]=PI_EMPTY;
  276.         draw_board();
  277.         myrefresh();
  278.         l_usleep(2500);
  279.         if (sound) {
  280.            printf("\7");
  281.            fflush(stdout);
  282.         }
  283.         for (k=0;k<GAME_WIDTH;k++)
  284.           board[i+4][k]=4;
  285.         draw_board();
  286.         myrefresh();
  287.         l_usleep(2500);
  288.         if (sound) {
  289.            printf("\7");
  290.            fflush(stdout);
  291.         }
  292.          }
  293.            
  294.         for (k = i; k > 0; k--)
  295.           for (j = 0; j < GAME_WIDTH; j++)
  296.         board[k+4][j] = board[k+3][j];
  297.         for (j = 0; j < GAME_WIDTH; j++)
  298.           board[4][j] = PI_EMPTY;
  299.         draw_board ();
  300.         myrefresh ();
  301.         i--;        /* Check the new row i */
  302.       }
  303.     }
  304.      switch (no_levels-dif_levels) {
  305.       case 0: break;
  306.       case 4: score+=40;
  307.       case 3: score+=30;
  308.       case 2: score+=20;
  309.       case 1: score+=10;
  310.         update_scores();
  311.         myrefresh();
  312.      }
  313.      
  314.  
  315.     if (pause_flag) {    /* If we are pausing after this drop ... */
  316.       pause_flag = 0;    /* Ensure we don't do so next time. */
  317.        draw_area();
  318.       hoopy_refresh();
  319.     }
  320.  
  321.     break;            /* End of fall - piece has hit floor */
  322.       }
  323.       
  324.       draw_piece (piece_no, orient, i, j, PD_ERASE);
  325.       i++;
  326.     }
  327.  
  328.     piece_no=piece_no_next;    /* Now the current piece is the one you */
  329.       orient=orient_next;      /* promised it would be. */
  330.       
  331.      if (total_time != 0)      /* This increases the difficulty level  */
  332.       total_time -= 100;       /* (he, he, he... :) */
  333.    }
  334. }
  335.  
  336. /*-------------------------------------------------------------------------*/
  337.